/* SPDX-License-Identifier: GPL-2.0 */
#ifndef SEMINIX_MMZONE_H
#define SEMINIX_MMZONE_H

enum zone_type {
    ZONE_DMA,
    ZONE_NORMAL,
    __MAX_NR_ZONES,
};

#ifndef __GENERATING_BOUNDS_H
#include <generated/bounds.h>
#include <seminix/spinlock.h>
#include <seminix/list.h>

/* Free memory management - zoned buddy allocator.  */
#ifndef CONFIG_FORCE_MAX_ZONEORDER
#define MAX_ORDER 11
#else
#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
#endif
#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))

struct free_area {
    struct list_head	free_list;
    unsigned long		nr_free;
};

struct per_cpu_pages {
    int count;		/* number of pages in the list */
    int high;		/* high watermark, emptying needed */
    int batch;		/* chunk size for buddy add/remove */

    struct list_head lists;
};

struct zone {
    struct pg_data	*zone_pgdat;

    struct per_cpu_pages __percpu *pcp;
    struct free_area free_area[MAX_ORDER];
    spinlock_t lock;

    unsigned long zone_start_pfn;
    unsigned long managed_pages;

    int initialized;
    const char  *name;
} ____cacheline_internodealigned_in_smp;

#define for_each_order(order)   \
    for (order = 0; order < MAX_ORDER; order++)

struct pg_data {
    struct zone zones[MAX_NR_ZONES];
    unsigned long start_pfn;
    atomic_long_t total_pages, reserved_pages, free_pages;
};

extern struct pg_data global_pg_data;
#define PG_DATA()		(&global_pg_data)

#define SETMANAGENRPAGES(name)                              \
static inline unsigned long nr_##name##_pages(void)           \
    { return atomic_long_read(&PG_DATA()->name##_pages); }  \
static inline void set_##name##_pages(unsigned long nr)       \
    { atomic_long_set(&PG_DATA()->name##_pages, nr); }      \
static inline void name##_pages_add(unsigned long nr)       \
    { atomic_long_add(nr, &PG_DATA()->name##_pages); }      \
static inline void name##_pages_sub(unsigned long nr)       \
    { atomic_long_sub(nr, &PG_DATA()->name##_pages); }      \
static inline void name##_pages_inc(void)                   \
    { atomic_long_inc(&PG_DATA()->name##_pages); }          \
static inline void name##_pages_dec(void)                   \
    { atomic_long_dec(&PG_DATA()->name##_pages); }          \

SETMANAGENRPAGES(total)
SETMANAGENRPAGES(reserved)
SETMANAGENRPAGES(free)

#undef SETMANAGENRPAGES

#endif /* !__GENERATING_BOUNDS_H */
#endif /* !SEMINIX_MMZONE_H */
